<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>工作流编辑器 - 优化版</title>
    <link rel="stylesheet" href="js/reactflow.css">
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        
        body { 
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 
            background-color: #f9f9f9;
        }
        
        .toolbar { 
            height: 60px; 
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            padding: 0 20px; 
            display: flex; 
            align-items: center; 
            gap: 15px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }
        
        .toolbar button { 
            background: rgba(255,255,255,0.2);
            border: 1px solid rgba(255,255,255,0.3);
            color: white;
            padding: 8px 16px; 
            border-radius: 6px; 
            cursor: pointer;
            font-size: 13px;
            transition: all 0.2s ease;
            backdrop-filter: blur(10px);
        }
        
        .toolbar button:hover { 
            background: rgba(255,255,255,0.3);
            transform: translateY(-1px);
        }
        
        .toolbar button:active { 
            transform: translateY(0);
        }
        
        .split { 
            display: flex; 
            height: calc(100vh - 60px); 
        }
        
        .split > div:first-child { 
            flex: 1; 
            background: #fff;
            border-right: 1px solid #e1e5e9;
        }
        
        .props { 
            width: 380px; 
            padding: 20px; 
            background: #fafbfc;
            overflow-y: auto;
            box-shadow: -2px 0 8px rgba(0,0,0,0.05);
        }
        
        .props label { 
            display: block; 
            margin: 12px 0 4px; 
            font-weight: 600;
            color: #2c3e50;
            font-size: 13px;
        }
        
        .props input, 
        .props textarea { 
            width: 100%; 
            padding: 10px 12px; 
            border: 1px solid #ddd; 
            border-radius: 6px; 
            font-size: 13px;
            transition: border-color 0.2s ease;
            background: white;
        }
        
        .props input:focus, 
        .props textarea:focus { 
            outline: none; 
            border-color: #667eea;
            box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
        }
        
        .props textarea { 
            resize: vertical; 
            line-height: 1.4;
        }
        
        .node-header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 15px;
            margin: -20px -20px 20px -20px;
            border-radius: 0;
            font-weight: 600;
            font-size: 14px;
        }
        
        .stats {
            color: rgba(255,255,255,0.9);
            font-size: 12px;
            font-weight: normal;
        }
        
        .help-section {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 6px;
            margin-top: 20px;
            border: 1px solid #e9ecef;
        }
        
        .help-section h4 {
            color: #495057;
            margin-bottom: 10px;
            font-size: 13px;
        }
        
        .help-section ul {
            list-style: none;
            padding: 0;
        }
        
        .help-section li {
            padding: 4px 0;
            font-size: 12px;
            color: #6c757d;
            position: relative;
            padding-left: 16px;
        }
        
        .help-section li:before {
            content: "•";
            position: absolute;
            left: 0;
            color: #667eea;
        }
        
        .error-message {
            background: #fee;
            color: #d63031;
            padding: 8px 12px;
            border-radius: 4px;
            font-size: 12px;
            margin-top: 8px;
            border: 1px solid #fab1a0;
        }

        /* 配置切换按钮样式 */
        .config-tabs {
            display: flex;
            gap: 10px;
            margin-bottom: 15px;
            padding: 10px 0;
            border-bottom: 1px solid #eee;
        }

        .config-tab {
            flex: 1;
            padding: 8px 12px;
            border: 1px solid #667eea;
            border-radius: 6px;
            cursor: pointer;
            font-size: 13px;
            font-weight: 500;
            text-align: center;
            transition: all 0.2s ease;
            background: white;
            color: #333;
        }

        .config-tab.active {
            background: #667eea;
            color: white;
        }

        .config-tab:hover:not(.active) {
            background: #f8f9ff;
            border-color: #5a67d8;
        }

        /* 根配置专用样式 */
        .root-config-info {
            margin-top: 20px;
            padding: 15px;
            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
            border-radius: 8px;
            border: 1px solid #dee2e6;
        }

        .root-config-info h4 {
            margin: 0 0 10px 0;
            color: #495057;
            font-size: 14px;
            font-weight: 600;
        }

        .root-config-info p {
            margin: 0;
            font-size: 12px;
            color: #6c757d;
            line-height: 1.6;
        }

        /* 空状态样式 */
        .empty-state {
            text-align: center;
            padding: 60px 20px;
            color: #6c757d;
        }

        .empty-state-icon {
            font-size: 48px;
            margin-bottom: 20px;
            opacity: 0.7;
        }

        .empty-state h3 {
            margin: 0 0 10px 0;
            font-size: 18px;
            font-weight: 500;
        }

        .empty-state p {
            margin: 0;
            font-size: 14px;
            line-height: 1.5;
        }

        .empty-state-tip {
            margin-top: 20px;
            padding: 10px;
            background: #f8f9fa;
            border-radius: 6px;
            font-size: 12px;
            border: 1px solid #e9ecef;
        }
        
        .position-info {
            background: #e8f4fd;
            color: #0984e3;
            padding: 8px 12px;
            border-radius: 4px;
            font-size: 12px;
            margin-top: 15px;
            border: 1px solid #74b9ff;
        }

        /* ReactFlow 自定义样式 */
        .react-flow__node {
            border-radius: 8px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.1);
            transition: box-shadow 0.2s ease;
        }
        
        .react-flow__node:hover {
            box-shadow: 0 4px 20px rgba(0,0,0,0.15);
        }
        
        .react-flow__node.selected {
            box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3);
        }

        /* 条件判断节点样式 */
        .react-flow__node[data-node-type="condition"] {
            background: linear-gradient(135deg, #ff9a56 0%, #ff6b4a 100%);
            border: 2px solid #ff6b4a;
            color: white;
            font-weight: 600;
            transform: rotate(45deg);
            width: 100px;
            height: 100px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .react-flow__node[data-node-type="condition"] .react-flow__node-default {
            transform: rotate(-45deg);
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        /* Start节点样式 */
        .react-flow__node[data-node-type="start"] {
            background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
            border: 2px solid #389e0d;
            color: white;
            border-radius: 50px;
        }

        /* End节点样式 */
        .react-flow__node[data-node-type="end"] {
            background: linear-gradient(135deg, #ff4d4f 0%, #cf1322 100%);
            border: 2px solid #cf1322;
            color: white;
            border-radius: 50px;
        }
        
        .react-flow__edge-path {
            stroke-width: 2;
            stroke: #667eea;
        }

        /* 箭头样式 */
        .react-flow__arrowhead {
            fill: #667eea;
        }

        /* 连接点（Handle）样式 */
        .react-flow__handle {
            width: 10px;
            height: 10px;
            background: #667eea;
            border: 2px solid white;
            border-radius: 50%;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
            opacity: 0;
            transition: all 0.2s ease;
        }

        /* 节点悬停时显示连接点 */
        .react-flow__node:hover .react-flow__handle,
        .react-flow__node.selected .react-flow__handle {
            opacity: 1;
        }

        /* 源连接点（输出） */
        .react-flow__handle.react-flow__handle-source {
            background: #52c41a;
            right: -5px;
        }

        /* 目标连接点（输入） */
        .react-flow__handle.react-flow__handle-target {
            background: #ff4d4f;
            left: -5px;
        }

        /* 连接点悬停效果 */
        .react-flow__handle:hover {
            transform: scale(1.3);
            box-shadow: 0 3px 8px rgba(0,0,0,0.3);
            opacity: 1 !important;
        }

        /* 条件节点的连接点 */
        .react-flow__node[data-node-type="condition"] .react-flow__handle {
            width: 12px;
            height: 12px;
        }

        /* 连接点标签 */
        .react-flow__handle::after {
            content: attr(data-label);
            position: absolute;
            top: -25px;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(0,0,0,0.8);
            color: white;
            padding: 2px 6px;
            border-radius: 4px;
            font-size: 10px;
            white-space: nowrap;
            opacity: 0;
            transition: opacity 0.2s ease;
            pointer-events: none;
        }

        .react-flow__handle:hover::after {
            opacity: 1;
        }

        /* 正在连线时的样式 */
        .react-flow__handle.connectingfrom {
            background: #faad14 !important;
            transform: scale(1.5);
            animation: pulse 1s infinite;
        }

        .react-flow__handle.connectingto {
            background: #13c2c2 !important;
            transform: scale(1.2);
        }

        @keyframes pulse {
            0% { box-shadow: 0 0 0 0 rgba(250, 173, 20, 0.7); }
            70% { box-shadow: 0 0 0 8px rgba(250, 173, 20, 0); }
            100% { box-shadow: 0 0 0 0 rgba(250, 173, 20, 0); }
        }

        /* SubFlow 节点特殊样式 */
        .react-flow__node[data-subflow="true"] {
            background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%) !important;
            border: 2px dashed #1890ff !important;
            box-shadow: 0 2px 8px rgba(24, 144, 255, 0.2) !important;
            min-height: 60px;
        }

        .react-flow__node[data-subflow="true"]:hover {
            box-shadow: 0 4px 16px rgba(24, 144, 255, 0.3) !important;
            transform: translateY(-1px);
        }

        .react-flow__node[data-subflow="true"].selected {
            box-shadow: 0 4px 20px rgba(24, 144, 255, 0.4) !important;
            border-color: #096dd9 !important;
        }

        /* SubFlow 图标动画 */
        .react-flow__node[data-subflow="true"]::after {
            content: '';
            position: absolute;
            top: -8px;
            right: -8px;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: rgba(24, 144, 255, 0.2);
            animation: subflow-pulse 2s infinite;
        }

        @keyframes subflow-pulse {
            0% { transform: scale(1); opacity: 0.8; }
            50% { transform: scale(1.2); opacity: 0.3; }
            100% { transform: scale(1); opacity: 0.8; }
        }

        /* Skill节点特殊样式 */
        .skill-node-indicator::after {
            content: '';
            position: absolute;
            top: -2px;
            left: -2px;
            right: -2px;
            bottom: -2px;
            border: 1px solid #722ed1;
            border-radius: 4px;
            background: rgba(114, 46, 209, 0.1);
            animation: skill-glow 3s infinite;
        }

        @keyframes skill-glow {
            0% { opacity: 0.3; transform: scale(1); }
            50% { opacity: 0.6; transform: scale(1.05); }
            100% { opacity: 0.3; transform: scale(1); }
        }

        /* Ctrl节点特殊样式 */
        .ctrl-node-indicator::after {
            content: '';
            position: absolute;
            top: -2px;
            left: -2px;
            right: -2px;
            bottom: -2px;
            border: 1px solid #ff7a45;
            border-radius: 4px;
            background: rgba(255, 122, 69, 0.1);
            animation: ctrl-pulse 2.5s infinite;
        }

        @keyframes ctrl-pulse {
            0% { opacity: 0.4; transform: scale(1); }
            50% { opacity: 0.7; transform: scale(1.08); }
            100% { opacity: 0.4; transform: scale(1); }
        }

        .react-flow__edge.animated .react-flow__edge-path {
            stroke-dasharray: 5;
            animation: dashdraw 0.5s linear infinite;
        }

        @keyframes dashdraw {
            from {
                stroke-dashoffset: 10;
            }
            to {
                stroke-dashoffset: 0;
            }
        }
        
        .react-flow__controls {
            box-shadow: 0 2px 12px rgba(0,0,0,0.1);
        }
        
        .react-flow__controls button {
            border: 1px solid #ddd;
            background: white;
        }
        
        .react-flow__controls button:hover {
            background: #f8f9fa;
        }

        /* 右键菜单样式 */
        .context-menu {
            position: fixed;
            background: white;
            border: 1px solid #ddd;
            border-radius: 6px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            padding: 4px 0;
            z-index: 1000;
            min-width: 150px;
        }

        .context-menu-item {
            padding: 8px 16px;
            cursor: pointer;
            font-size: 13px;
            color: #333;
            border: none;
            background: none;
            width: 100%;
            text-align: left;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .context-menu-item:hover {
            background: #f5f5f5;
        }

        .context-menu-item.danger:hover {
            background: #fff2f0;
            color: #ff4d4f;
        }

        .context-menu-divider {
            height: 1px;
            background: #e8e8e8;
            margin: 4px 0;
        }

        /* SubFlow弹窗样式 */
        .subflow-modal {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            z-index: 1000;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .subflow-modal-content {
            background: white;
            border-radius: 8px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
            max-width: 90%;
            max-height: 90%;
            width: 1200px;
            height: 800px;
            overflow: hidden;
            display: flex;
            flex-direction: column;
        }

        .subflow-modal-header {
            padding: 16px 20px;
            border-bottom: 1px solid #e8e8e8;
            display: flex;
            justify-content: space-between;
            align-items: center;
            background: #f5f5f5;
        }

        .subflow-modal-title {
            font-size: 16px;
            font-weight: 600;
            color: #333;
            margin: 0;
        }

        .subflow-modal-close {
            background: none;
            border: none;
            font-size: 24px;
            cursor: pointer;
            color: #666;
            padding: 0;
            width: 30px;
            height: 30px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 4px;
        }

        .subflow-modal-close:hover {
            background: #e8e8e8;
        }

        .subflow-modal-body {
            flex: 1;
            padding: 0;
            overflow: hidden;
        }

        .subflow-loading {
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100%;
            font-size: 14px;
            color: #666;
        }

        .subflow-error {
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100%;
            font-size: 14px;
            color: #ff4d4f;
            text-align: center;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    </style>
</head>
<body>
    <div id="root"></div>
    
    <script src="js/react.development.js"></script>
    <script src="js/react-dom.development.js"></script>
    <script src="js/babel.min.js"></script>
    <script src="js/reactflow.js"></script>
    
    <script type="text/babel">
        const { useState, useEffect, useCallback, useRef, useMemo } = React;
        const { ReactFlowProvider, ReactFlow, Controls, Background, addEdge, applyNodeChanges, applyEdgeChanges, Handle, Position } = window.ReactFlow;

        /* ------------ 常量定义 ------------ */
        const STORAGE_KEY = 'workflow-data';
        const DEFAULT_NODE_STYLE = {
            background: '#fff',
            border: '2px solid #667eea',
            borderRadius: '8px',
            padding: '12px',
            fontSize: '13px',
            fontWeight: '500',
            color: '#2c3e50'
        };

        /* ------------ 初始空配置 ------------ */
        const emptyFlow = {
            Cmds: [
                { Name: 'Start', Cmd: 'Start', Args: { Type: 'Start', 'Next.0': 'Node2' }, position: { x: 50, y: 50 } },
                { Name: 'Node2', Cmd: 'DeviceIntentionVoice', Args: { Type: 'Normal', 'Next.0': 'End' }, position: { x: 250, y: 50 } },
                { Name: 'End', Cmd: 'Echo', Args: { Type: 'End' }, position: { x: 450, y: 50 } }
            ]
        };

        /* ------------ 自定义节点组件 ------------ */
        const CustomNode = ({ data, selected }) => {
            const nodeType = data['data-node-type'] || 'normal';
            const isCondition = nodeType === 'condition';
            const isStart = nodeType === 'start';
            const isEnd = nodeType === 'end';
            const isSubFlow = data.Args?.Type === 'SubFlow';
            const isSkillNode = data.Cmd && data.Cmd.includes('skill');
            const isCtrlNode = data.Cmd && data.Cmd.startsWith('ctrl');

            return (
                <div 
                    style={{
                        ...data.style,
                        position: 'relative',
                        minWidth: isCondition ? '100px' : '120px',
                        minHeight: isCondition ? '100px' : (isSubFlow ? '60px' : '40px'),
                        display: 'flex',
                        alignItems: 'center',
                        justifyContent: 'center',
                        textAlign: 'center',
                        cursor: 'pointer',
                        border: isSubFlow ? '2px dashed #1890ff' : data.style?.border,
                        background: isSubFlow 
                            ? 'linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%)' 
                            : data.style?.background,
                        transition: isSubFlow ? 'all 0.3s ease' : 'none'
                    }}
                    onMouseEnter={isSubFlow ? (e) => {
                        e.currentTarget.style.transform = 'scale(1.05)';
                        e.currentTarget.style.boxShadow = '0 6px 16px rgba(24, 144, 255, 0.3)';
                    } : undefined}
                    onMouseLeave={isSubFlow ? (e) => {
                        e.currentTarget.style.transform = 'scale(1)';
                        e.currentTarget.style.boxShadow = '0 4px 12px rgba(24, 144, 255, 0.2)';
                    } : undefined}
                >
                    {/* SubFlow 图标标识 */}
                    {isSubFlow && (
                        <div 
                            style={{
                                position: 'absolute',
                                top: '-8px',
                                right: '-8px',
                                width: '20px',
                                height: '20px',
                                background: 'linear-gradient(135deg, #1890ff 0%, #096dd9 100%)',
                                borderRadius: '50%',
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'center',
                                fontSize: '10px',
                                color: 'white',
                                fontWeight: 'bold',
                                border: '2px solid white',
                                boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
                                zIndex: 10,
                                cursor: 'help'
                            }}
                            title={`子流程节点\n文件名: ${data.Cmd}\n类型: ${data.Args?.Type}`}
                        >
                            ⚙️
                        </div>
                    )}
                    
                    {/* Skill 节点标识 */}
                    {isSkillNode && (
                        <div 
                            style={{
                                position: 'absolute',
                                top: '-8px',
                                left: '-8px',
                                width: '18px',
                                height: '18px',
                                background: 'linear-gradient(135deg, #722ed1 0%, #531dab 100%)',
                                borderRadius: '4px',
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'center',
                                fontSize: '9px',
                                color: 'white',
                                fontWeight: 'bold',
                                border: '2px solid white',
                                boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
                                zIndex: 9,
                                cursor: 'help'
                            }}
                            title={`Skill节点\n位于skill文件夹\n文件名: ${data.Cmd}`}
                        >
                            S
                        </div>
                    )}
                    
                    {/* Ctrl 节点标识 */}
                    {isCtrlNode && (
                        <div 
                            style={{
                                position: 'absolute',
                                top: '-8px',
                                left: isSkillNode ? '12px' : '-8px', // 如果同时是skill节点，则右移避免重叠
                                width: '18px',
                                height: '18px',
                                background: 'linear-gradient(135deg, #ff7a45 0%, #fa541c 100%)',
                                borderRadius: '4px',
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'center',
                                fontSize: '9px',
                                color: 'white',
                                fontWeight: 'bold',
                                border: '2px solid white',
                                boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
                                zIndex: 8,
                                cursor: 'help'
                            }}
                            title={`控制节点\n位于ctrl文件夹\n文件名: ${data.Cmd}`}
                        >
                            C
                        </div>
                    )}
                    {/* 输入连接点 - 除了Start节点都有 */}
                    {!isStart && (
                        <Handle
                            type="target"
                            position={Position.Left}
                            data-label="输入"
                            style={{
                                background: '#ff4d4f',
                                border: '2px solid white',
                                width: '10px',
                                height: '10px',
                                left: '-5px'
                            }}
                        />
                    )}

                    {/* 节点内容 */}
                    <div style={{ 
                        transform: isCondition ? 'rotate(-45deg)' : 'none',
                        maxWidth: isCondition ? '80px' : '100%',
                        wordBreak: 'break-word',
                        fontSize: isSubFlow ? '11px' : '12px',
                        lineHeight: '1.2',
                        padding: isSubFlow ? '4px' : '0'
                    }}>
                        <div style={{ 
                            fontWeight: isSubFlow ? '600' : 'normal',
                            color: isSubFlow ? '#1890ff' : 'inherit'
                        }}>
                            {data.Name}
                        </div>
                        
                        {isSubFlow && data.Cmd && (
                            <div style={{ 
                                fontSize: '9px', 
                                color: '#1890ff',
                                background: 'rgba(24, 144, 255, 0.1)',
                                padding: '1px 4px',
                                borderRadius: '3px',
                                marginTop: '2px',
                                fontWeight: '500'
                            }}>
                                📄 {data.Cmd}
                            </div>
                        )}
                        
                        {!isSubFlow && data.Cmd && data.Cmd !== data.Name && (
                            <div style={{ 
                                fontSize: '10px', 
                                opacity: 0.8, 
                                marginTop: '2px' 
                            }}>
                                {data.Cmd}
                            </div>
                        )}
                        
                        {/* 条件判断节点的特殊显示 */}
                        {isCondition && (
                            <div style={{
                                fontSize: '8px',
                                color: '#fa8c16',
                                marginTop: '2px',
                                transform: 'rotate(45deg)', // 抵消父级的旋转
                                maxWidth: '120px',
                                wordBreak: 'break-word'
                            }}>
                                {/* 显示条件判断的分支数量 */}
                                {data.Args && Object.keys(data.Args).filter(key => key.startsWith('Next.')).length > 0 && (
                                    <div style={{ marginBottom: '1px' }}>
                                        {Object.keys(data.Args).filter(key => key.startsWith('Next.')).length} 分支
                                    </div>
                                )}
                                {/* 显示判断条件（如果有InParams中的Condition字段）*/}
                                {data.InParams?.Condition && (
                                    <div style={{ 
                                        fontSize: '7px',
                                        opacity: 0.8,
                                        fontStyle: 'italic'
                                    }}>
                                        {data.InParams.Condition.length > 20 
                                            ? data.InParams.Condition.substring(0, 20) + '...' 
                                            : data.InParams.Condition}
                                    </div>
                                )}
                            </div>
                        )}
                        
                        {isSubFlow && (
                            <>
                                <div style={{ 
                                    fontSize: '8px', 
                                    color: '#595959',
                                    marginTop: '1px'
                                }}>
                                    子流程
                                </div>
                                <div style={{ 
                                    fontSize: '7px', 
                                    color: '#1890ff',
                                    marginTop: '1px',
                                    opacity: 0.8,
                                    fontStyle: 'italic'
                                }}>
                                    点击查看详情
                                </div>
                            </>
                        )}
                        
                        {isSkillNode && (
                            <div style={{ 
                                fontSize: '8px', 
                                color: '#722ed1',
                                marginTop: '1px',
                                fontWeight: '500'
                            }}>
                                🔧 Skill文件夹
                            </div>
                        )}
                        
                        {isCtrlNode && (
                            <div style={{ 
                                fontSize: '8px', 
                                color: '#ff7a45',
                                marginTop: '1px',
                                fontWeight: '500'
                            }}>
                                🎮 Ctrl文件夹
                            </div>
                        )}
                    </div>

                    {/* 输出连接点 - 除了End节点都有 */}
                    {!isEnd && (
                        <>
                            <Handle
                                type="source"
                                position={Position.Right}
                                id="output-main"
                                data-label={isCondition ? "分支0" : "输出"}
                                style={{
                                    background: '#52c41a',
                                    border: '2px solid white',
                                    width: '10px',
                                    height: '10px',
                                    right: '-5px',
                                    top: '50%'
                                }}
                            />
                            
                            {/* 条件节点的第二个输出点 */}
                            {isCondition && (
                                <Handle
                                    type="source"
                                    position={Position.Bottom}
                                    id="output-fail"
                                    data-label="分支1"
                                    style={{
                                        background: '#ff4d4f',
                                        border: '2px solid white',
                                        width: '10px',
                                        height: '10px',
                                        bottom: '-5px',
                                        left: '50%',
                                        transform: 'translateX(-50%)'
                                    }}
                                />
                            )}
                        </>
                    )}
                </div>
            );
        };

        /* 节点类型定义 */
        const nodeTypes = {
            custom: CustomNode
        };

        /* ------------ 布局算法 ------------ */
        const autoLayoutNodes = (nodes, edges) => {
            // 构建邻接表
            const adjacencyList = {};
            const inDegree = {};
            const levels = {};
            
            // 初始化
            nodes.forEach(node => {
                adjacencyList[node.id] = [];
                inDegree[node.id] = 0;
            });
            
            // 构建图
            edges.forEach(edge => {
                adjacencyList[edge.source].push(edge.target);
                inDegree[edge.target] = (inDegree[edge.target] || 0) + 1;
            });
            
            // 拓扑排序 + 层级分配
            const queue = [];
            nodes.forEach(node => {
                if (inDegree[node.id] === 0) {
                    queue.push(node.id);
                    levels[node.id] = 0;
                }
            });
            
            while (queue.length > 0) {
                const current = queue.shift();
                const currentLevel = levels[current];
                
                adjacencyList[current].forEach(neighbor => {
                    inDegree[neighbor]--;
                    levels[neighbor] = Math.max(levels[neighbor] || 0, currentLevel + 1);
                    
                    if (inDegree[neighbor] === 0) {
                        queue.push(neighbor);
                    }
                });
            }
            
            // 按层级分组
            const levelGroups = {};
            nodes.forEach(node => {
                const level = levels[node.id] || 0;
                if (!levelGroups[level]) {
                    levelGroups[level] = [];
                }
                levelGroups[level].push(node);
            });
            
            // 计算新位置
            const levelWidth = 250;
            const nodeHeight = 120;
            const startX = 100;
            const startY = 100;
            
            const layoutNodes = nodes.map(node => {
                const level = levels[node.id] || 0;
                const nodesInLevel = levelGroups[level];
                const indexInLevel = nodesInLevel.findIndex(n => n.id === node.id);
                
                const x = startX + level * levelWidth;
                const y = startY + indexInLevel * nodeHeight;
                
                return {
                    ...node,
                    position: { x, y }
                };
            });
            
            return layoutNodes;
        };

        /* ------------ 工具函数 ------------ */
        const loadFile = () => {
            try {
                const data = localStorage.getItem(STORAGE_KEY);
                return data ? JSON.parse(data) : emptyFlow;
            } catch (error) {
                console.error('Failed to load data from localStorage:', error);
                return emptyFlow;
            }
        };

        const saveFile = (data) => {
            try {
                localStorage.setItem(STORAGE_KEY, JSON.stringify(data, null, 2));
                console.log('Data saved to localStorage');
            } catch (error) {
                console.error('Failed to save data to localStorage:', error);
            }
        };

        /* ------------ 自定义Hook：数据转换 ------------ */
        const useFlowData = () => {
            const convertToReactFlow = useCallback((cfg, useAutoLayout = true) => {
                const nodes = cfg.Cmds.map(c => {
                    // 根据节点类型确定样式和属性
                    let nodeStyle = { ...DEFAULT_NODE_STYLE };
                    let nodeType = 'default';
                    let nodeAttrs = {};

                    // 判断节点类型
                    if (c.Args?.Type === 'Start' || c.Name === 'Start') {
                        nodeAttrs['data-node-type'] = 'start';
                        nodeStyle = {
                            ...nodeStyle,
                            background: 'linear-gradient(135deg, #52c41a 0%, #389e0d 100%)',
                            border: '2px solid #389e0d',
                            color: 'white',
                            borderRadius: '50px'
                        };
                    } else if (c.Args?.Type === 'End' || c.Cmd === 'Echo') {
                        nodeAttrs['data-node-type'] = 'end';
                        nodeStyle = {
                            ...nodeStyle,
                            background: 'linear-gradient(135deg, #ff4d4f 0%, #cf1322 100%)',
                            border: '2px solid #cf1322',
                            color: 'white',
                            borderRadius: '50px'
                        };
                    } else if (c.Cmd === 'Condition' || c.Args?.Type === 'Condition') {
                        nodeAttrs['data-node-type'] = 'condition';
                        nodeStyle = {
                            ...nodeStyle,
                            background: 'linear-gradient(135deg, #ff9a56 0%, #ff6b4a 100%)',
                            border: '2px solid #ff6b4a',
                            color: 'white',
                            borderRadius: '8px'
                        };
                    } else if (c.Args?.Type === 'SubFlow') {
                        nodeAttrs['data-node-type'] = 'subflow';
                        nodeStyle = {
                            ...nodeStyle,
                            background: 'linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%)',
                            border: '2px dashed #1890ff',
                            color: '#096dd9',
                            borderRadius: '12px',
                            position: 'relative',
                            boxShadow: '0 4px 12px rgba(24, 144, 255, 0.2)'
                        };
                    }

                    return {
                        id: c.Name,
                        type: 'custom', // 使用自定义节点类型
                        position: c.position || { x: 0, y: 0 },
                        data: {
                            ...c,
                            label: c.Name,
                            style: nodeStyle,
                            'data-node-type': nodeAttrs['data-node-type'] || 'normal'
                        },
                        ...nodeAttrs
                    };
                });

                const edges = [];
                cfg.Cmds.forEach(c => {
                    Object.keys(c.Args || {})
                        .filter(k => k.startsWith('Next.'))
                        .forEach(k => {
                            const targetId = c.Args[k];
                            if (targetId && cfg.Cmds.some(cmd => cmd.Name === targetId)) {
                                // 为条件节点的不同分支使用不同的样式
                                let edgeStyle = { strokeWidth: 2, stroke: '#667eea' };
                                let edgeLabel = '';
                                
                                if (c.Cmd === 'Condition') {
                                    // 提取分支编号
                                    const branchIndex = k.split('.')[1];
                                    edgeLabel = branchIndex;
                                    
                                    // 为不同分支使用不同颜色
                                    if (branchIndex === '0') {
                                        edgeStyle.stroke = '#52c41a'; // 绿色 - 分支0
                                    } else if (branchIndex === '1') {
                                        edgeStyle.stroke = '#ff4d4f'; // 红色 - 分支1
                                    } else if (branchIndex === '2') {
                                        edgeStyle.stroke = '#1890ff'; // 蓝色 - 分支2
                                    } else if (branchIndex === '3') {
                                        edgeStyle.stroke = '#722ed1'; // 紫色 - 分支3
                                    } else {
                                        edgeStyle.stroke = '#fa8c16'; // 橙色 - 其他分支
                                    }
                                }

                                edges.push({
                                    id: `${c.Name}-${targetId}`,
                                    source: c.Name,
                                    target: targetId,
                                    animated: true,
                                    label: edgeLabel,
                                    labelStyle: { 
                                        fill: edgeStyle.stroke, 
                                        fontWeight: 'bold',
                                        fontSize: '16px'
                                    },
                                    markerEnd: {
                                        type: 'arrowclosed',
                                        color: edgeStyle.stroke,
                                        width: 20,
                                        height: 20
                                    },
                                    style: edgeStyle
                                });
                            }
                        });
                });

                // 如果没有位置信息或需要自动布局，则使用自动布局
                const needsLayout = useAutoLayout || nodes.some(node => 
                    !node.position || (node.position.x === 0 && node.position.y === 0)
                );
                
                const finalNodes = needsLayout ? autoLayoutNodes(nodes, edges) : nodes;

                return { nodes: finalNodes, edges };
            }, []);

            const convertFromReactFlow = useCallback((nodes, rootConfig = {}) => {
                const cfg = {
                    Name: rootConfig.Name || "工作流配置",
                    Dispatcher: rootConfig.Dispatcher || "Route",
                    CmdFailEndCmdName: rootConfig.CmdFailEndCmdName || "FailSound",
                    Cmds: []
                };
                
                nodes.forEach(n => {
                    if (n.data.Name) {
                        const cmdObj = {
                            Name: n.data.Name || n.id,
                            Args: n.data.Args || {},
                            position: n.position
                        };
                        
                        // 只有在Cmd字段存在时才添加
                        if (n.data.Cmd) {
                            cmdObj.Cmd = n.data.Cmd;
                        }
                        
                        // 添加InParams和OutParams字段（如果存在）
                        if (n.data.InParams) {
                            cmdObj.InParams = n.data.InParams;
                        }
                        if (n.data.OutParams) {
                            cmdObj.OutParams = n.data.OutParams;
                        }
                        
                        // 添加AlreadyParse字段（如果存在）
                        if (n.data.AlreadyParse !== undefined) {
                            cmdObj.AlreadyParse = n.data.AlreadyParse;
                        }
                        
                        cfg.Cmds.push(cmdObj);
                    }
                });
                return cfg;
            }, []);

            return { convertToReactFlow, convertFromReactFlow };
        };

        /* ------------ SubFlow查看器组件 ------------ */
        const SubFlowViewer = ({ data }) => {
            const [subNodes, setSubNodes] = useState([]);
            const [subEdges, setSubEdges] = useState([]);
            
            const { convertToReactFlow } = useFlowData();
            
            useEffect(() => {
                if (data) {
                    try {
                        const { nodes, edges } = convertToReactFlow(data, true);
                        setSubNodes(nodes);
                        setSubEdges(edges);
                    } catch (error) {
                        console.error('转换SubFlow数据失败:', error);
                    }
                }
            }, [data, convertToReactFlow]);

            return (
                <div style={{ width: '100%', height: '100%', position: 'relative' }}>
                    <ReactFlow
                        nodes={subNodes}
                        edges={subEdges}
                        nodeTypes={nodeTypes}
                        fitView
                        fitViewOptions={{ padding: 0.2 }}
                        defaultViewport={{ x: 0, y: 0, zoom: 0.8 }}
                        nodesDraggable={false}
                        nodesConnectable={false}
                        elementsSelectable={false}
                        zoomOnScroll={true}
                        panOnScroll={false}
                        style={{ background: '#fafafa' }}
                    >
                        <Background />
                        <Controls />
                    </ReactFlow>
                    
                    {/* 子流程信息面板 */}
                    <div style={{
                        position: 'absolute',
                        top: '10px',
                        right: '10px',
                        background: 'rgba(255, 255, 255, 0.95)',
                        padding: '12px',
                        borderRadius: '6px',
                        boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
                        fontSize: '12px',
                        color: '#666',
                        maxWidth: '200px'
                    }}>
                        <div style={{ fontWeight: '600', color: '#333', marginBottom: '4px' }}>
                            {data.Name || '子流程'}
                        </div>
                        <div>节点数量: {data.Cmds?.length || 0}</div>
                        {data.Dispatcher && (
                            <div>分发器: {data.Dispatcher}</div>
                        )}
                        {data.CmdFailEndCmdName && (
                            <div>失败处理: {data.CmdFailEndCmdName}</div>
                        )}
                    </div>
                </div>
            );
        };

        /* ------------ 主组件 ------------ */
        function App() {
            const [nodes, setNodes] = useState([]);
            const [edges, setEdges] = useState([]);
            const [selected, setSelected] = useState(null);
            const [jsonError, setJsonError] = useState('');
            const [contextMenu, setContextMenu] = useState(null);
            const [rootConfig, setRootConfig] = useState({
                Name: "工作流配置",
                Dispatcher: "Route", 
                CmdFailEndCmdName: "FailSound"
            });
            const [showRootConfig, setShowRootConfig] = useState(false);
            const [subflowModal, setSubflowModal] = useState(null); // SubFlow弹窗状态
            const fileInputRef = useRef(null);

            const { convertToReactFlow, convertFromReactFlow } = useFlowData();

            // 计算当前配置
            const currentConfig = useMemo(() => convertFromReactFlow(nodes, rootConfig), [nodes, rootConfig, convertFromReactFlow]);

            /* 初始化数据 */
            useEffect(() => {
                // 检查URL参数中是否指定了特定服务文件
                const urlParams = new URLSearchParams(window.location.search);
                const serviceFile = urlParams.get('service');
                
                if (serviceFile) {
                    // 尝试从services文件夹加载指定的服务配置
                    fetch(`services/${serviceFile}`)
                        .then(response => {
                            if (!response.ok) {
                                throw new Error(`HTTP error! status: ${response.status}`);
                            }
                            return response.json();
                        })
                        .then(config => {
                            if (!config.Cmds || !Array.isArray(config.Cmds)) {
                                throw new Error('Invalid service file format: missing Cmds array');
                            }
                            const { nodes: initialNodes, edges: initialEdges } = convertToReactFlow(config);
                            setNodes(initialNodes);
                            setEdges(initialEdges);
                            
                            // 设置根配置
                            setRootConfig({
                                Name: config.Name || "工作流配置",
                                Dispatcher: config.Dispatcher || "Route",
                                CmdFailEndCmdName: config.CmdFailEndCmdName || "FailSound"
                            });
                            
                            // 更新页面标题
                            document.title = `工作流编辑器 - ${config.Name || serviceFile}`;
                        })
                        .catch(error => {
                            console.error('Failed to load service file:', error);
                            // 加载失败时使用默认数据
                            const initialData = loadFile();
                            const { nodes: initialNodes, edges: initialEdges } = convertToReactFlow(initialData);
                            setNodes(initialNodes);
                            setEdges(initialEdges);
                            
                            // 设置默认根配置
                            if (initialData.Name || initialData.Dispatcher || initialData.CmdFailEndCmdName) {
                                setRootConfig({
                                    Name: initialData.Name || "工作流配置",
                                    Dispatcher: initialData.Dispatcher || "Route",
                                    CmdFailEndCmdName: initialData.CmdFailEndCmdName || "FailSound"
                                });
                            }
                            
                            alert(`加载服务文件失败: ${error.message}\n将使用本地存储的数据`);
                        });
                } else {
                    // 没有指定服务文件，使用本地存储的数据
                    const initialData = loadFile();
                    const { nodes: initialNodes, edges: initialEdges } = convertToReactFlow(initialData);
                    setNodes(initialNodes);
                    setEdges(initialEdges);
                    
                    // 设置根配置（如果本地数据有的话）
                    if (initialData.Name || initialData.Dispatcher || initialData.CmdFailEndCmdName) {
                        setRootConfig({
                            Name: initialData.Name || "工作流配置",
                            Dispatcher: initialData.Dispatcher || "Route",
                            CmdFailEndCmdName: initialData.CmdFailEndCmdName || "FailSound"
                        });
                    }
                }
            }, [convertToReactFlow]);

            /* 自动保存（防抖） */
            useEffect(() => {
                if (nodes.length === 0) return;

                const timeoutId = setTimeout(() => {
                    saveFile(currentConfig);
                }, 1000); // 1秒防抖

                return () => clearTimeout(timeoutId);
            }, [currentConfig]);

            /* 文件操作 */
            const handleImport = useCallback((e) => {
                const file = e.target.files[0];
                if (!file) return;

                const reader = new FileReader();
                reader.onload = (event) => {
                    try {
                        const config = JSON.parse(event.target.result);
                        if (!config.Cmds || !Array.isArray(config.Cmds)) {
                            throw new Error('Invalid file format: missing Cmds array');
                        }
                        const { nodes: newNodes, edges: newEdges } = convertToReactFlow(config);
                        setNodes(newNodes);
                        setEdges(newEdges);
                        setSelected(null);
                        
                        // 更新根配置
                        setRootConfig({
                            Name: config.Name || "工作流配置",
                            Dispatcher: config.Dispatcher || "Route",
                            CmdFailEndCmdName: config.CmdFailEndCmdName || "FailSound"
                        });
                        
                        alert(`成功导入 ${config.Cmds.length} 个节点`);
                    } catch (error) {
                        alert('导入失败：JSON格式错误或文件格式不正确');
                        console.error('Import error:', error);
                    }
                };
                reader.readAsText(file);
                e.target.value = ''; // 重置input，允许重复导入同一文件
            }, [convertToReactFlow]);

            const handleExport = useCallback(() => {
                const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-');
                const blob = new Blob([JSON.stringify(currentConfig, null, 2)], {
                    type: 'application/json'
                });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `workflow-${timestamp}.json`;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
            }, [currentConfig]);

            /* ReactFlow 回调 */
            const onNodesChange = useCallback((changes) => {
                setNodes(nodes => applyNodeChanges(changes, nodes));
            }, []);

            const onEdgesChange = useCallback((changes) => {
                changes.forEach(change => {
                    if (change.type === 'remove') {
                        // 查找要删除的边
                        const edgeToRemove = edges.find(edge => edge.id === change.id);
                        if (edgeToRemove) {
                            // 从源节点的Args中移除对应的Next字段
                            setNodes(prevNodes => 
                                prevNodes.map(node => {
                                    if (node.id === edgeToRemove.source) {
                                        const newArgs = { ...node.data.Args };
                                        
                                        // 查找并删除对应的Next字段
                                        Object.keys(newArgs).forEach(key => {
                                            if (key.startsWith('Next.') && newArgs[key] === edgeToRemove.target) {
                                                delete newArgs[key];
                                            }
                                        });
                                        
                                        return {
                                            ...node,
                                            data: {
                                                ...node.data,
                                                Args: newArgs
                                            }
                                        };
                                    }
                                    return node;
                                })
                            );
                        }
                    }
                });
                
                setEdges(edges => applyEdgeChanges(changes, edges));
            }, [edges]);

            const onConnect = useCallback((params) => {
                // 检查源节点是否为条件节点
                const sourceNode = nodes.find(n => n.id === params.source);
                let edgeStyle = { strokeWidth: 2, stroke: '#667eea' };
                let edgeLabel = '';
                let nextKey = 'Next.0';
                
                if (sourceNode?.data.Cmd === 'Condition') {
                    // 根据连接点ID确定分支类型
                    if (params.sourceHandle === 'output-main') {
                        edgeStyle.stroke = '#52c41a';
                        edgeLabel = '✓';
                        nextKey = 'Next.0';
                    } else if (params.sourceHandle === 'output-fail') {
                        edgeStyle.stroke = '#ff4d4f';
                        edgeLabel = '✗';
                        nextKey = 'Next.1';
                    } else {
                        // 如果没有指定连接点，则询问用户
                        const branchType = window.prompt('请选择连接类型:\n输入 "0" 表示分支0\n输入 "1" 表示分支1\n输入 "2" 表示分支2...', '0');
                        if (branchType !== null && branchType.match(/^\d+$/)) {
                            nextKey = `Next.${branchType}`;
                            edgeLabel = branchType;
                            
                            // 为不同分支使用不同颜色
                            if (branchType === '0') {
                                edgeStyle.stroke = '#52c41a'; // 绿色
                            } else if (branchType === '1') {
                                edgeStyle.stroke = '#ff4d4f'; // 红色
                            } else if (branchType === '2') {
                                edgeStyle.stroke = '#1890ff'; // 蓝色
                            } else if (branchType === '3') {
                                edgeStyle.stroke = '#722ed1'; // 紫色
                            } else {
                                edgeStyle.stroke = '#fa8c16'; // 橙色
                            }
                        } else {
                            return; // 取消连接
                        }
                    }
                } else {
                    // 普通节点，查找下一个可用的Next.X
                    const sourceNodeData = sourceNode?.data;
                    if (sourceNodeData?.Args) {
                        let nextIndex = 0;
                        while (sourceNodeData.Args[`Next.${nextIndex}`]) {
                            nextIndex++;
                        }
                        nextKey = `Next.${nextIndex}`;
                    }
                }

                // 更新源节点的Args中的Next字段
                setNodes(prevNodes => 
                    prevNodes.map(node => {
                        if (node.id === params.source) {
                            return {
                                ...node,
                                data: {
                                    ...node.data,
                                    Args: {
                                        ...node.data.Args,
                                        [nextKey]: params.target
                                    }
                                }
                            };
                        }
                        return node;
                    })
                );

                // 添加边
                setEdges(edges => addEdge({ 
                    ...params, 
                    animated: true,
                    label: edgeLabel,
                    labelStyle: { 
                        fill: edgeStyle.stroke, 
                        fontWeight: 'bold',
                        fontSize: '16px'
                    },
                    markerEnd: {
                        type: 'arrowclosed',
                        color: edgeStyle.stroke,
                        width: 20,
                        height: 20
                    },
                    style: edgeStyle,
                    data: { nextKey } // 保存nextKey用于删除时使用
                }, edges));
            }, [nodes]);

            /* 节点选择和编辑 */
            const onNodeClick = useCallback((_, node) => {
                // 如果是SubFlow节点，显示弹窗
                if (node.data.Args?.Type === 'SubFlow' && node.data.Cmd) {
                    handleSubFlowClick(node.data.Cmd, node.data.Name);
                } else {
                    setSelected(node);
                    setJsonError('');
                }
                setContextMenu(null); // 关闭右键菜单
            }, []);

            /* 处理SubFlow节点点击 */
            const handleSubFlowClick = useCallback(async (subflowFile, nodeName) => {
                setSubflowModal({
                    isOpen: true,
                    title: `子流程: ${nodeName}`,
                    file: subflowFile,
                    loading: true,
                    error: null,
                    data: null
                });

                try {
                    let response;
                    
                    // 根据文件名前缀确定搜索顺序
                    if (subflowFile.startsWith('ctrl')) {
                        // ctrl开头，先尝试ctrl文件夹
                        response = await fetch(`services/ctrl/${subflowFile}.json`);
                        
                        if (!response.ok) {
                            // 如果ctrl文件夹中没有，尝试skill文件夹
                            response = await fetch(`services/skill/${subflowFile}.json`);
                        }
                        
                        if (!response.ok) {
                            // 最后尝试services根目录
                            response = await fetch(`services/${subflowFile}.json`);
                        }
                    } else if (subflowFile.includes('skill')) {
                        // skill相关，先尝试skill文件夹
                        response = await fetch(`services/skill/${subflowFile}.json`);
                        
                        if (!response.ok) {
                            // 如果skill文件夹中没有，尝试services根目录
                            response = await fetch(`services/${subflowFile}.json`);
                        }
                    } else {
                        // 其他情况，先尝试services根目录
                        response = await fetch(`services/${subflowFile}.json`);
                        
                        if (!response.ok) {
                            // 然后尝试skill文件夹
                            response = await fetch(`services/skill/${subflowFile}.json`);
                        }
                        
                        if (!response.ok) {
                            // 最后尝试ctrl文件夹
                            response = await fetch(`services/ctrl/${subflowFile}.json`);
                        }
                    }

                    if (!response.ok) {
                        throw new Error(`找不到子流程文件: ${subflowFile}.json`);
                    }

                    const subflowData = await response.json();
                    
                    setSubflowModal(prev => ({
                        ...prev,
                        loading: false,
                        data: subflowData
                    }));
                } catch (error) {
                    setSubflowModal(prev => ({
                        ...prev,
                        loading: false,
                        error: error.message
                    }));
                }
            }, []);

            /* 关闭SubFlow弹窗 */
            const closeSubflowModal = useCallback(() => {
                setSubflowModal(null);
            }, []);

            /* 连线右键点击 */
            const onEdgeContextMenu = useCallback((event, edge) => {
                event.preventDefault();
                
                setContextMenu({
                    x: event.clientX,
                    y: event.clientY,
                    edge: edge,
                    type: 'edge'
                });
            }, []);

            /* 关闭右键菜单 */
            const closeContextMenu = useCallback(() => {
                setContextMenu(null);
            }, []);

            /* 全局点击事件 */
            useEffect(() => {
                const handleClick = () => {
                    setContextMenu(null);
                };
                
                document.addEventListener('click', handleClick);
                return () => document.removeEventListener('click', handleClick);
            }, []);

            const updateNodeField = useCallback((field, value) => {
                if (!selected) return;

                const oldId = selected.id;
                
                setNodes(nodes =>
                    nodes.map(n => {
                        if (n.id === selected.id) {
                            const updatedNode = {
                                ...n,
                                data: { ...n.data, [field]: value }
                            };
                            // 如果更新的是Name字段，同时更新id和label
                            if (field === 'Name') {
                                updatedNode.id = value;
                                updatedNode.data.label = value;
                            }
                            return updatedNode;
                        }
                        return n;
                    })
                );

                // 更新selected状态
                setSelected(prev => {
                    const updatedSelected = {
                        ...prev,
                        data: { ...prev.data, [field]: value }
                    };
                    if (field === 'Name') {
                        updatedSelected.id = value;
                        updatedSelected.data.label = value;
                    }
                    return updatedSelected;
                });

                // 如果更新的是Name字段，同时更新相关的edges和其他节点的Args
                if (field === 'Name') {
                    // 更新edges
                    setEdges(edges =>
                        edges.map(edge => ({
                            ...edge,
                            source: edge.source === oldId ? value : edge.source,
                            target: edge.target === oldId ? value : edge.target,
                            id: edge.source === oldId ? `${value}-${edge.target}` :
                                edge.target === oldId ? `${edge.source}-${value}` : edge.id
                        }))
                    );
                    
                    // 更新其他节点Args中的Next字段引用
                    setNodes(prevNodes =>
                        prevNodes.map(node => {
                            const newArgs = { ...node.data.Args };
                            let argsChanged = false;
                            
                            Object.keys(newArgs).forEach(key => {
                                if (key.startsWith('Next.') && newArgs[key] === oldId) {
                                    newArgs[key] = value;
                                    argsChanged = true;
                                }
                            });
                            
                            if (argsChanged) {
                                return {
                                    ...node,
                                    data: {
                                        ...node.data,
                                        Args: newArgs
                                    }
                                };
                            }
                            return node;
                        })
                    );
                }
            }, [selected]);

            // 更新根配置字段
            const updateRootField = useCallback((field, value) => {
                setRootConfig(prev => ({
                    ...prev,
                    [field]: value
                }));
            }, []);

            const updateNodeArgs = useCallback((jsonString) => {
                setJsonError('');
                try {
                    const args = JSON.parse(jsonString);
                    
                    // 更新节点的Args
                    updateNodeField('Args', args);
                    
                    // 重新生成连线以反映Args中Next字段的变化
                    if (selected) {
                        // 获取当前所有节点以便查找目标节点
                        const allNodes = nodes.map(n => 
                            n.id === selected.id ? { ...n, data: { ...n.data, Args: args } } : n
                        );
                        
                        // 删除从此节点出发的所有连线
                        setEdges(prevEdges => {
                            // 保留不是从此节点出发的连线
                            const otherEdges = prevEdges.filter(edge => edge.source !== selected.id);
                            
                            // 根据新的Args重新创建连线
                            const newEdges = [];
                            Object.keys(args).forEach(key => {
                                if (key.startsWith('Next.') && args[key]) {
                                    const targetId = args[key];
                                    // 检查目标节点是否存在
                                    if (allNodes.some(node => node.id === targetId)) {
                                        let edgeStyle = { strokeWidth: 2, stroke: '#667eea' };
                                        let edgeLabel = '';
                                        
                                        // 条件节点的特殊样式
                                        if (selected.data.Cmd === 'Condition') {
                                            if (key === 'Next.0') {
                                                edgeStyle.stroke = '#52c41a';
                                                edgeLabel = '✓';
                                            } else if (key === 'Next.1') {
                                                edgeStyle.stroke = '#ff4d4f';
                                                edgeLabel = '✗';
                                            }
                                        }
                                        
                                        newEdges.push({
                                            id: `${selected.id}-${targetId}`,
                                            source: selected.id,
                                            target: targetId,
                                            animated: true,
                                            label: edgeLabel,
                                            labelStyle: { 
                                                fill: edgeStyle.stroke, 
                                                fontWeight: 'bold',
                                                fontSize: '16px'
                                            },
                                            markerEnd: {
                                                type: 'arrowclosed',
                                                color: edgeStyle.stroke,
                                                width: 20,
                                                height: 20
                                            },
                                            style: edgeStyle,
                                            data: { nextKey: key }
                                        });
                                    }
                                }
                            });
                            
                            return [...otherEdges, ...newEdges];
                        });
                    }
                } catch (error) {
                    setJsonError('Args JSON格式错误：请检查括号、引号和逗号是否正确');
                }
            }, [updateNodeField, selected, nodes]);

            const updateNodeInParams = useCallback((jsonString) => {
                try {
                    const inParams = JSON.parse(jsonString);
                    updateNodeField('InParams', inParams);
                } catch (error) {
                    console.warn('InParams JSON parse error:', error);
                }
            }, [updateNodeField]);

            const updateNodeOutParams = useCallback((jsonString) => {
                try {
                    const outParams = JSON.parse(jsonString);
                    updateNodeField('OutParams', outParams);
                } catch (error) {
                    console.warn('OutParams JSON parse error:', error);
                }
            }, [updateNodeField]);

            /* 添加新节点 */
            const addNewNode = useCallback(() => {
                const newId = `Node_${Date.now()}`;
                const newNode = {
                    id: newId,
                    type: 'default',
                    position: {
                        x: Math.random() * 400 + 100,
                        y: Math.random() * 300 + 100
                    },
                    data: {
                        Name: newId,
                        Cmd: 'NewCommand',
                        Args: { Type: 'Normal' },
                        InParams: {},
                        OutParams: [],
                        label: newId,
                        style: DEFAULT_NODE_STYLE
                    }
                };
                setNodes(nodes => [...nodes, newNode]);
                setSelected(newNode); // 自动选中新添加的节点
            }, []);

            /* 添加条件判断节点 */
            const addConditionNode = useCallback(() => {
                const newId = `条件判断_${Date.now()}`;
                const newNode = {
                    id: newId,
                    type: 'custom', // 使用自定义节点类型
                    position: {
                        x: Math.random() * 400 + 100,
                        y: Math.random() * 300 + 100
                    },
                    data: {
                        Name: newId,
                        Cmd: 'Condition',
                        Args: { 
                            Type: 'Condition',
                            mode: 'First',
                            'Next.0': '',  // 分支0
                            'Next.1': ''   // 分支1
                        },
                        InParams: {
                            Condition: ''  // 默认空条件，用户需要填写
                        },
                        OutParams: [],
                        label: newId,
                        style: {
                            ...DEFAULT_NODE_STYLE,
                            background: 'linear-gradient(135deg, #ff9a56 0%, #ff6b4a 100%)',
                            border: '2px solid #ff6b4a',
                            color: 'white',
                            borderRadius: '8px'
                        },
                        'data-node-type': 'condition'
                    }
                };
                setNodes(nodes => [...nodes, newNode]);
                setSelected(newNode); // 自动选中新添加的节点
            }, []);

            /* 删除连线 */
            const deleteEdge = useCallback((edgeId) => {
                const edgeToRemove = edges.find(edge => edge.id === edgeId);
                if (edgeToRemove) {
                    // 从源节点的Args中移除对应的Next字段
                    setNodes(prevNodes => 
                        prevNodes.map(node => {
                            if (node.id === edgeToRemove.source) {
                                const newArgs = { ...node.data.Args };
                                
                                // 查找并删除对应的Next字段
                                Object.keys(newArgs).forEach(key => {
                                    if (key.startsWith('Next.') && newArgs[key] === edgeToRemove.target) {
                                        delete newArgs[key];
                                    }
                                });
                                
                                return {
                                    ...node,
                                    data: {
                                        ...node.data,
                                        Args: newArgs
                                    }
                                };
                            }
                            return node;
                        })
                    );
                    
                    // 删除连线
                    setEdges(prevEdges => prevEdges.filter(edge => edge.id !== edgeId));
                }
                setContextMenu(null);
            }, [edges]);

            /* 编辑连线 */
            const editEdge = useCallback((edge) => {
                const sourceNode = nodes.find(n => n.id === edge.source);
                const targetNode = nodes.find(n => n.id === edge.target);
                
                if (!sourceNode || !targetNode) return;

                // 如果是条件节点，允许更改分支类型
                if (sourceNode.data.Cmd === 'Condition') {
                    const currentBranch = edge.label || '0';
                    const newBranch = window.prompt(
                        `当前连线: ${sourceNode.data.Name} → ${targetNode.data.Name}\n` +
                        `当前分支: 分支${currentBranch}\n\n` +
                        `请选择新的分支类型:\n输入 "0" 表示分支0\n输入 "1" 表示分支1\n输入 "2" 表示分支2...`,
                        currentBranch
                    );
                    
                    if (newBranch !== null && newBranch.match(/^\d+$/)) {
                        // 删除旧连线
                        deleteEdge(edge.id);
                        
                        // 创建新连线
                        const newNextKey = `Next.${newBranch}`;
                        let edgeStyle = { strokeWidth: 2, stroke: '#667eea' };
                        let edgeLabel = newBranch;
                        
                        // 为不同分支使用不同颜色
                        if (newBranch === '0') {
                            edgeStyle.stroke = '#52c41a'; // 绿色
                        } else if (newBranch === '1') {
                            edgeStyle.stroke = '#ff4d4f'; // 红色
                        } else if (newBranch === '2') {
                            edgeStyle.stroke = '#1890ff'; // 蓝色
                        } else if (newBranch === '3') {
                            edgeStyle.stroke = '#722ed1'; // 紫色
                        } else {
                            edgeStyle.stroke = '#fa8c16'; // 橙色
                        }
                        
                        // 更新源节点Args
                        setNodes(prevNodes => 
                            prevNodes.map(node => {
                                if (node.id === sourceNode.id) {
                                    return {
                                        ...node,
                                        data: {
                                            ...node.data,
                                            Args: {
                                                ...node.data.Args,
                                                [newNextKey]: targetNode.id
                                            }
                                        }
                                    };
                                }
                                return node;
                            })
                        );
                        
                        // 添加新连线
                        setEdges(prevEdges => [...prevEdges, {
                            id: `${sourceNode.id}-${targetNode.id}`,
                            source: sourceNode.id,
                            target: targetNode.id,
                            animated: true,
                            label: edgeLabel,
                            labelStyle: { 
                                fill: edgeStyle.stroke, 
                                fontWeight: 'bold',
                                fontSize: '16px'
                            },
                            markerEnd: {
                                type: 'arrowclosed',
                                color: edgeStyle.stroke,
                                width: 20,
                                height: 20
                            },
                            style: edgeStyle,
                            data: { nextKey: newNextKey }
                        }]);
                    }
                } else {
                    // 普通节点，显示连线信息
                    alert(`连线信息:\n源节点: ${sourceNode.data.Name}\n目标节点: ${targetNode.data.Name}\n类型: 普通连接`);
                }
                
                setContextMenu(null);
            }, [nodes, deleteEdge]);

            /* 重新连接 */
            const reconnectEdge = useCallback((edge) => {
                // 获取所有可用的目标节点
                const availableNodes = nodes.filter(n => n.id !== edge.source);
                const nodeOptions = availableNodes.map(n => `${n.id}: ${n.data.Name || n.id}`).join('\n');
                
                const newTargetId = window.prompt(
                    `重新连接\n源节点: ${edge.source}\n当前目标: ${edge.target}\n\n` +
                    `可选目标节点:\n${nodeOptions}\n\n` +
                    `请输入新的目标节点ID:`,
                    edge.target
                );
                
                if (newTargetId && newTargetId !== edge.target && nodes.some(n => n.id === newTargetId)) {
                    // 删除旧连线
                    deleteEdge(edge.id);
                    
                    // 创建新连接（模拟onConnect行为）
                    const sourceNode = nodes.find(n => n.id === edge.source);
                    let edgeStyle = { strokeWidth: 2, stroke: '#667eea' };
                    let edgeLabel = '';
                    let nextKey = 'Next.0';
                    
                    if (sourceNode?.data.Cmd === 'Condition') {
                        const branchType = window.prompt('请选择连接类型:\n输入 "0" 表示分支0\n输入 "1" 表示分支1\n输入 "2" 表示分支2...', '0');
                        if (branchType !== null && branchType.match(/^\d+$/)) {
                            nextKey = `Next.${branchType}`;
                            edgeLabel = branchType;
                            
                            // 为不同分支使用不同颜色
                            if (branchType === '0') {
                                edgeStyle.stroke = '#52c41a'; // 绿色
                            } else if (branchType === '1') {
                                edgeStyle.stroke = '#ff4d4f'; // 红色
                            } else if (branchType === '2') {
                                edgeStyle.stroke = '#1890ff'; // 蓝色
                            } else if (branchType === '3') {
                                edgeStyle.stroke = '#722ed1'; // 紫色
                            } else {
                                edgeStyle.stroke = '#fa8c16'; // 橙色
                            }
                        } else {
                            return;
                        }
                    } else {
                        // 找到下一个可用的Next.X
                        const sourceNodeData = sourceNode?.data;
                        if (sourceNodeData?.Args) {
                            let nextIndex = 0;
                            while (sourceNodeData.Args[`Next.${nextIndex}`]) {
                                nextIndex++;
                            }
                            nextKey = `Next.${nextIndex}`;
                        }
                    }

                    // 更新源节点Args
                    setNodes(prevNodes => 
                        prevNodes.map(node => {
                            if (node.id === edge.source) {
                                return {
                                    ...node,
                                    data: {
                                        ...node.data,
                                        Args: {
                                            ...node.data.Args,
                                            [nextKey]: newTargetId
                                        }
                                    }
                                };
                            }
                            return node;
                        })
                    );

                    // 添加新连线
                    setEdges(prevEdges => [...prevEdges, {
                        id: `${edge.source}-${newTargetId}`,
                        source: edge.source,
                        target: newTargetId,
                        animated: true,
                        label: edgeLabel,
                        labelStyle: { 
                            fill: edgeStyle.stroke, 
                            fontWeight: 'bold',
                            fontSize: '16px'
                        },
                        markerEnd: {
                            type: 'arrowclosed',
                            color: edgeStyle.stroke,
                            width: 20,
                            height: 20
                        },
                        style: edgeStyle,
                        data: { nextKey }
                    }]);
                }
                
                setContextMenu(null);
            }, [nodes, deleteEdge]);
            const reLayout = useCallback(() => {
                const layoutedNodes = autoLayoutNodes(nodes, edges);
                setNodes(layoutedNodes);
            }, [nodes, edges]);

            /* 删除选中节点 */
            const deleteSelectedNode = useCallback(() => {
                if (!selected) return;
                
                const confirmed = window.confirm(`确定删除节点 "${selected.data.Name || selected.id}" 吗？`);
                if (!confirmed) return;

                setNodes(nodes => nodes.filter(n => n.id !== selected.id));
                setEdges(edges => edges.filter(e => e.source !== selected.id && e.target !== selected.id));
                setSelected(null);
            }, [selected]);

            /* 清空所有节点 */
            const clearAll = useCallback(() => {
                const confirmed = window.confirm('确定清空所有节点吗？此操作不可撤销。');
                if (!confirmed) return;

                setNodes([]);
                setEdges([]);
                setSelected(null);
            }, []);

            return (
                <>
                    <div className="toolbar">
                        <input
                            type="file"
                            accept=".json"
                            ref={fileInputRef}
                            onChange={handleImport}
                            style={{ display: 'none' }}
                        />
                        <button onClick={() => window.open('services-index.html', '_blank')} style={{ background: 'rgba(40,167,69,0.2)', borderColor: 'rgba(40,167,69,0.3)' }}>
                            🏠 服务管理
                        </button>
                        <button onClick={() => fileInputRef.current?.click()}>
                            📁 导入 JSON
                        </button>
                        <button onClick={handleExport}>
                            💾 导出 JSON
                        </button>
                        <button onClick={addNewNode}>
                            ➕ 添加节点
                        </button>
                        <button onClick={addConditionNode} style={{ background: 'rgba(255,154,86,0.2)', borderColor: 'rgba(255,107,74,0.3)' }}>
                            🔀 条件判断
                        </button>
                        <button onClick={reLayout} style={{ background: 'rgba(52,168,83,0.2)', borderColor: 'rgba(52,168,83,0.3)' }}>
                            🔄 重新布局
                        </button>
                        {selected && (
                            <button onClick={deleteSelectedNode} style={{ background: 'rgba(255,59,48,0.2)', borderColor: 'rgba(255,59,48,0.3)' }}>
                                🗑️ 删除节点
                            </button>
                        )}
                        <button onClick={clearAll} style={{ background: 'rgba(255,149,0,0.2)', borderColor: 'rgba(255,149,0,0.3)' }}>
                            🧹 清空所有
                        </button>
                        <div className="stats">
                            节点数: {nodes.length} | 连接数: {edges.length}
                        </div>
                    </div>

                    <div className="split">
                        <ReactFlowProvider>
                            <ReactFlow
                                nodes={nodes}
                                edges={edges}
                                nodeTypes={nodeTypes}
                                onNodesChange={onNodesChange}
                                onEdgesChange={onEdgesChange}
                                onConnect={onConnect}
                                onNodeClick={onNodeClick}
                                onEdgeContextMenu={onEdgeContextMenu}
                                onPaneClick={closeContextMenu}
                                fitView
                                attributionPosition="top-right"
                                proOptions={{ hideAttribution: true }}
                                defaultViewport={{ x: 0, y: 0, zoom: 1 }}
                                minZoom={0.2}
                                maxZoom={2}
                                snapToGrid={true}
                                snapGrid={[15, 15]}
                                connectionLineType="smoothstep"
                                connectionLineStyle={{ strokeWidth: 2, stroke: '#667eea' }}
                                deleteKeyCode="Delete"
                                selectNodesOnDrag={true}
                                elementsSelectable={true}
                                nodesConnectable={true}
                                nodesDraggable={true}
                                edgesUpdatable={true}
                                edgesFocusable={true}
                            >
                                <Controls showZoom={true} showFitView={true} showInteractive={true} />
                                <Background variant="dots" gap={15} size={1} color="#e1e5e9" />
                            </ReactFlow>
                        </ReactFlowProvider>

                        <div className="props">
                            {/* 配置切换按钮 */}
                            <div className="config-tabs">
                                <button 
                                    className={`config-tab ${!showRootConfig ? 'active' : ''}`}
                                    onClick={() => setShowRootConfig(false)}
                                >
                                    🔧 节点配置 {selected ? `(${selected.data.Name || selected.id})` : '(未选择)'}
                                </button>
                                <button 
                                    className={`config-tab ${showRootConfig ? 'active' : ''}`}
                                    onClick={() => setShowRootConfig(true)}
                                >
                                    🏠 根配置
                                </button>
                            </div>

                            {showRootConfig ? (
                                /* 根配置面板 */
                                <div>
                                    <div className="node-header">
                                        工作流根配置
                                    </div>

                                    <label>工作流名称</label>
                                    <input
                                        value={rootConfig.Name}
                                        onChange={e => updateRootField('Name', e.target.value)}
                                        placeholder="输入工作流名称"
                                    />

                                    <label>分发器类型</label>
                                    <select
                                        value={rootConfig.Dispatcher}
                                        onChange={e => updateRootField('Dispatcher', e.target.value)}
                                        style={{
                                            width: '100%',
                                            padding: '10px 12px',
                                            border: '1px solid #ddd',
                                            borderRadius: '6px',
                                            fontSize: '13px',
                                            background: 'white'
                                        }}
                                    >
                                        <option value="Route">Route</option>
                                        <option value="Direct">Direct</option>
                                        <option value="Broadcast">Broadcast</option>
                                        <option value="Random">Random</option>
                                    </select>

                                    <label>失败结束命令</label>
                                    <input
                                        value={rootConfig.CmdFailEndCmdName}
                                        onChange={e => updateRootField('CmdFailEndCmdName', e.target.value)}
                                        placeholder="失败时执行的结束命令"
                                    />

                                    <div className="root-config-info">
                                        <h4>配置说明</h4>
                                        <p>
                                            • <strong>工作流名称</strong>：显示在标题栏和导出文件中<br/>
                                            • <strong>分发器类型</strong>：控制命令执行方式<br/>
                                            • <strong>失败结束命令</strong>：当工作流执行失败时调用的节点名称
                                        </p>
                                    </div>
                                </div>
                            ) : selected ? (
                                /* 节点配置面板 */
                                <div>
                                    <div className="node-header">
                                        编辑节点：{selected.data.Name || selected.id}
                                    </div>

                                    <label>节点名称</label>
                                    <input
                                        value={selected.data.Name || selected.id}
                                        onChange={e => updateNodeField('Name', e.target.value)}
                                        placeholder="输入节点名称"
                                    />

                                    <label>命令类型</label>
                                    <input
                                        value={selected.data.Cmd || ''}
                                        onChange={e => updateNodeField('Cmd', e.target.value)}
                                        placeholder="输入命令类型"
                                    />

                                    {/* 条件判断节点的专门配置 */}
                                    {(selected.data.Cmd === 'Condition' || selected.data.Args?.Type === 'Condition') && (
                                        <div style={{
                                            background: '#fff7e6',
                                            border: '1px solid #ffd666',
                                            borderRadius: '6px',
                                            padding: '12px',
                                            margin: '12px 0'
                                        }}>
                                            <h4 style={{ margin: '0 0 8px 0', color: '#fa8c16' }}>
                                                🔀 条件判断配置
                                            </h4>
                                            
                                            <label>判断条件 (Condition)</label>
                                            <input
                                                value={selected.data.InParams?.Condition || ''}
                                                onChange={e => {
                                                    const newInParams = { ...(selected.data.InParams || {}) };
                                                    if (e.target.value) {
                                                        newInParams.Condition = e.target.value;
                                                    } else {
                                                        delete newInParams.Condition;
                                                    }
                                                    updateNodeField('InParams', newInParams);
                                                }}
                                                placeholder='例如: @Check.AA 或 js:(某个条件表达式)'
                                                style={{
                                                    fontFamily: 'Monaco, Consolas, "Courier New", monospace',
                                                    fontSize: '12px'
                                                }}
                                            />
                                            <div style={{ fontSize: '11px', color: '#666', marginTop: '4px' }}>
                                                • 使用 @变量名 引用其他节点的输出<br/>
                                                • 使用 js:(表达式) 编写JavaScript判断条件<br/>
                                                • 例如：js:('@上个节点.status' === 'success')
                                            </div>
                                            
                                            <label style={{ marginTop: '12px' }}>分支配置</label>
                                            <div>
                                                {selected.data.Args && Object.keys(selected.data.Args)
                                                    .filter(key => key.startsWith('Next.'))
                                                    .sort((a, b) => parseInt(a.split('.')[1]) - parseInt(b.split('.')[1]))
                                                    .map((nextKey, index) => (
                                                        <div key={nextKey} style={{ 
                                                            display: 'flex', 
                                                            alignItems: 'center', 
                                                            gap: '8px', 
                                                            marginBottom: '4px' 
                                                        }}>
                                                            <span style={{ 
                                                                minWidth: '60px', 
                                                                fontSize: '12px',
                                                                color: '#1890ff',
                                                                fontWeight: '500'
                                                            }}>
                                                                分支{index}:
                                                            </span>
                                                            <input
                                                                value={selected.data.Args[nextKey] || ''}
                                                                onChange={e => {
                                                                    const newArgs = { ...selected.data.Args };
                                                                    newArgs[nextKey] = e.target.value;
                                                                    updateNodeField('Args', newArgs);
                                                                }}
                                                                placeholder="目标节点名称"
                                                                style={{ flex: 1, fontSize: '12px' }}
                                                            />
                                                            <button
                                                                onClick={() => {
                                                                    const newArgs = { ...selected.data.Args };
                                                                    delete newArgs[nextKey];
                                                                    updateNodeField('Args', newArgs);
                                                                }}
                                                                style={{
                                                                    background: '#ff4d4f',
                                                                    color: 'white',
                                                                    border: 'none',
                                                                    borderRadius: '4px',
                                                                    padding: '4px 8px',
                                                                    fontSize: '12px',
                                                                    cursor: 'pointer'
                                                                }}
                                                            >
                                                                删除
                                                            </button>
                                                        </div>
                                                    ))}
                                                <button
                                                    onClick={() => {
                                                        const newArgs = { ...selected.data.Args };
                                                        const existingKeys = Object.keys(newArgs).filter(key => key.startsWith('Next.'));
                                                        const nextIndex = existingKeys.length;
                                                        newArgs[`Next.${nextIndex}`] = '';
                                                        updateNodeField('Args', newArgs);
                                                    }}
                                                    style={{
                                                        background: '#1890ff',
                                                        color: 'white',
                                                        border: 'none',
                                                        borderRadius: '4px',
                                                        padding: '6px 12px',
                                                        fontSize: '12px',
                                                        cursor: 'pointer',
                                                        marginTop: '8px'
                                                    }}
                                                >
                                                    ➕ 添加分支
                                                </button>
                                            </div>
                                        </div>
                                    )}

                                    <label>参数 (Args - JSON格式)</label>
                                    <textarea
                                        rows={6}
                                        value={JSON.stringify(selected.data.Args || {}, null, 2)}
                                        onChange={e => updateNodeArgs(e.target.value)}
                                        placeholder="输入JSON格式的参数"
                                        style={{
                                            fontFamily: 'Monaco, Consolas, "Courier New", monospace',
                                            fontSize: '12px',
                                            border: jsonError ? '1px solid #ff4d4f' : '1px solid #ddd'
                                        }}
                                    />
                                    {jsonError && (
                                        <div className="error-message">
                                            {jsonError}
                                        </div>
                                    )}

                                    <label>输入参数 (InParams - JSON格式)</label>
                                    <textarea
                                        rows={4}
                                        value={JSON.stringify(selected.data.InParams || {}, null, 2)}
                                        onChange={e => updateNodeInParams(e.target.value)}
                                        placeholder='例如: {"devNo": "@Query.sn"}'
                                        style={{
                                            fontFamily: 'Monaco, Consolas, "Courier New", monospace',
                                            fontSize: '12px',
                                            border: '1px solid #ddd'
                                        }}
                                    />

                                    <label>输出参数 (OutParams - JSON格式)</label>
                                    <textarea
                                        rows={4}
                                        value={JSON.stringify(selected.data.OutParams || [], null, 2)}
                                        onChange={e => updateNodeOutParams(e.target.value)}
                                        placeholder='例如: ["result", "status"]'
                                        style={{
                                            fontFamily: 'Monaco, Consolas, "Courier New", monospace',
                                            fontSize: '12px',
                                            border: '1px solid #ddd'
                                        }}
                                    />

                                    {/* 显示AlreadyParse字段（如果存在） */}
                                    {selected.data.AlreadyParse !== undefined && (
                                        <>
                                            <label>已解析标记 (AlreadyParse)</label>
                                            <select
                                                value={selected.data.AlreadyParse ? 'true' : 'false'}
                                                onChange={e => updateNodeField('AlreadyParse', e.target.value === 'true')}
                                                style={{
                                                    width: '100%',
                                                    padding: '10px 12px',
                                                    border: '1px solid #ddd',
                                                    borderRadius: '6px',
                                                    fontSize: '13px',
                                                    background: 'white'
                                                }}
                                            >
                                                <option value="false">false</option>
                                                <option value="true">true</option>
                                            </select>
                                        </>
                                    )}

                                    {/* 条件判断节点的特殊提示 */}
                                    {selected.data.Cmd === 'Condition' && (
                                        <div style={{
                                            background: '#fff3cd',
                                            border: '1px solid #ffeaa7',
                                            padding: '10px',
                                            borderRadius: '6px',
                                            marginTop: '15px',
                                            fontSize: '12px',
                                            color: '#856404'
                                        }}>
                                            <strong>条件判断节点说明：</strong>
                                            <ul style={{ margin: '5px 0', paddingLeft: '20px' }}>
                                                <li>Next.0: 条件为真时的下一个节点</li>
                                                <li>Next.1: 条件为假时的下一个节点</li>
                                                <li>mode: First表示第一个匹配的条件</li>
                                                <li>连线时会自动标记✓（成功）和✗（失败）</li>
                                            </ul>
                                        </div>
                                    )}

                                    <div className="position-info">
                                        位置: ({Math.round(selected.position?.x || 0)}, {Math.round(selected.position?.y || 0)})
                                    </div>
                                </div>
                            ) : (
                                /* 未选择节点时显示 */
                                <div className="empty-state">
                                    <div className="empty-state-icon">🔧</div>
                                    <h3>节点配置面板</h3>
                                    <p>
                                        点击工作流中的任意节点<br/>
                                        开始编辑节点属性
                                    </p>
                                    <div className="empty-state-tip">
                                        💡 提示：使用上方的"根配置"切换到工作流全局设置
                                    </div>
                                </div>
                            )}
                        </div>
                    </div>

                    {/* 右键菜单 */}
                    {contextMenu && contextMenu.type === 'edge' && (
                        <div 
                            className="context-menu"
                            style={{ 
                                left: contextMenu.x, 
                                top: contextMenu.y 
                            }}
                            onClick={e => e.stopPropagation()}
                        >
                            <button 
                                className="context-menu-item"
                                onClick={() => editEdge(contextMenu.edge)}
                            >
                                <span>✏️</span>
                                编辑连线
                            </button>
                            <button 
                                className="context-menu-item"
                                onClick={() => reconnectEdge(contextMenu.edge)}
                            >
                                <span>🔄</span>
                                重新连接
                            </button>
                            <div className="context-menu-divider"></div>
                            <button 
                                className="context-menu-item danger"
                                onClick={() => deleteEdge(contextMenu.edge.id)}
                            >
                                <span>🗑️</span>
                                删除连线
                            </button>
                        </div>
                    )}

                    {/* SubFlow弹窗 */}
                    {subflowModal?.isOpen && (
                        <div className="subflow-modal" onClick={closeSubflowModal}>
                            <div className="subflow-modal-content" onClick={e => e.stopPropagation()}>
                                <div className="subflow-modal-header">
                                    <h3 className="subflow-modal-title">
                                        {subflowModal.title}
                                        {subflowModal.file && (
                                            <span style={{ fontSize: '12px', color: '#666', fontWeight: 'normal' }}>
                                                {' '}({subflowModal.file}.json)
                                            </span>
                                        )}
                                    </h3>
                                    <button className="subflow-modal-close" onClick={closeSubflowModal}>
                                        ×
                                    </button>
                                </div>
                                <div className="subflow-modal-body">
                                    {subflowModal.loading ? (
                                        <div className="subflow-loading">
                                            <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
                                                <div style={{ 
                                                    width: '20px', 
                                                    height: '20px', 
                                                    border: '2px solid #f3f3f3',
                                                    borderTop: '2px solid #1890ff',
                                                    borderRadius: '50%',
                                                    animation: 'spin 1s linear infinite' 
                                                }}></div>
                                                加载子流程中...
                                            </div>
                                        </div>
                                    ) : subflowModal.error ? (
                                        <div className="subflow-error">
                                            <div>
                                                <div style={{ fontSize: '16px', marginBottom: '8px' }}>❌</div>
                                                <div>加载失败</div>
                                                <div style={{ fontSize: '12px', opacity: 0.7, marginTop: '4px' }}>
                                                    {subflowModal.error}
                                                </div>
                                            </div>
                                        </div>
                                    ) : subflowModal.data ? (
                                        <SubFlowViewer data={subflowModal.data} />
                                    ) : null}
                                </div>
                            </div>
                        </div>
                    )}
                </>
            );
        }

        ReactDOM.createRoot(document.getElementById('root')).render(<App />);
    </script>
</body>
</html>
